package com.xyrl.project.common.system.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xyrl.common.util.HttpClientUtil;
import com.xyrl.common.util.ObjectUtil;
import com.xyrl.common.util.RedisUtil;
import com.xyrl.project.common.constant.CacheConstant;
import com.xyrl.project.common.system.dao.AreasMapper;
import com.xyrl.project.common.system.entity.Areas;
import com.xyrl.project.common.system.service.AreasService;
import com.xyrl.project.common.system.vo.AreasVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName AreasServiceImpl
 * @Description TODO
 * @Author Administrator
 * @Date 2019/12/18 14:23
 * @Version 1.0
 */
@Service
@Slf4j
public class AreasServiceImpl extends ServiceImpl<AreasMapper, Areas> implements AreasService {

    /**
     * 区域信息
     */
    private final String DISTRICTS = "districts";
    /**
     * 城市名称
     */
    private final String NAME = "name";
    /**
     * 城市编码
     */
    private final String ADCODE = "adcode";
    /**
     * 定位信息
     */
    private final String CENTER = "center";
    /**
     * 顶级code
     */
    private final String ROOT_CODE = "100000";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncAreas() {
        try {
            String areas = HttpClientUtil.get("https://restapi.amap.com/v3/config/district?subdistrict=4&key=bb4198a1f146184af53322d424732f6b");
            JSONObject jsonObject = JSONObject.parseObject(areas);
            log.info(areas);
            if (jsonObject.containsKey(DISTRICTS) && ObjectUtil.isNotEmpty(jsonObject.getJSONArray(DISTRICTS))) {
                //获取到国家及下面所有的信息 开始循环插入，这里可以写成递归调用，但是不如这样方便查看、理解
                JSONArray countryAll = jsonObject.getJSONArray(DISTRICTS);
                //取得国家下的城市
                List<Areas> areasList = new ArrayList<>();
                baseMapper.clearAreas();
                for (int i = 0; i < countryAll.size(); i++) {
                    long time = System.currentTimeMillis();
                    iterationAreas(countryAll.getJSONObject(i), areasList, "-1");
                    log.info("解析区域代码耗时：{}", (System.currentTimeMillis() - time));
                }
                log.info("城市信息长度:{}", areasList.size());
                this.saveBatch(areasList);
            }
            RedisUtil.delKey(CacheConstant.BASIC_AREAS_ALL);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    @Cacheable(value = "common.areas#86400")
    public List<AreasVo> getAll() {
        long time = System.currentTimeMillis();
        AreasVo areas = RedisUtil.getData(CacheConstant.BASIC_AREAS_ALL, AreasVo.class);
        if (null == areas) {
            areas = getAllAreas();
            RedisUtil.setData(CacheConstant.BASIC_AREAS_ALL, areas);
        }
        log.info("取得地区耗时:{}",(System.currentTimeMillis()-time));
        return areas.getChildren();
    }

    /**
     * 取得所有地区数据
     *
     * @return
     */
    private AreasVo getAllAreas() {
        List<Areas> lists = baseMapper.selectList(new QueryWrapper<>());
        return itemAreas(lists);
    }

    /**
     * 组装数据结构
     *
     * @param lists
     * @return
     */
    private AreasVo itemAreas(List<Areas> lists) {
        Map<String, List<AreasVo>> maps = new HashMap<>();
        Set<String> codes = new HashSet<>();
        for (Areas areas : lists) {
            AreasVo vo = new AreasVo();
            BeanUtils.copyProperties(areas, vo);
            vo.setSort(Integer.parseInt(vo.getCode()));
            if (ObjectUtil.isEmpty(areas.getParentCode()) || "-1".equalsIgnoreCase(areas.getParentCode())) {
                codes.add(areas.getParentCode());
                continue;
            }
            if (maps.containsKey(vo.getParentCode())) {
                maps.get(vo.getParentCode()).add(vo);
            } else {
                List<AreasVo> children = new ArrayList<>();
                children.add(vo);
                maps.put(vo.getParentCode(), children);
            }
        }
        AreasVo vo = new AreasVo();
        vo.setCode(ROOT_CODE);
        //拼接数据
        forEach(maps, vo);
        return vo;
    }

    private static void forEach(Map<String, List<AreasVo>> collect, AreasVo areasVo) {
        List<AreasVo> treeMenuNodes = collect.get(areasVo.getCode());
        if (collect.get(areasVo.getCode()) != null) {
            //排序
            treeMenuNodes.sort((u1, u2) -> u1.getCode().compareTo(u2.getCode()));
            treeMenuNodes.stream().sorted(Comparator.comparing(AreasVo::getSort)).collect(Collectors.toList());
            areasVo.setChildren(treeMenuNodes);
            areasVo.getChildren().forEach(t -> {
                forEach(collect, t);
            });
        }
    }


//    private Areas getAllByDb() {
//        Areas areas = findByCode(ROOT_CODE);
//        // 获取一级省份
//        List<Areas> list = this.findByParentCode(areas.getCode());
//        for (Areas item : list) {
//            // 获取省份下全部区域
//            item.setNextList(this.findByProvince(item.getCode()));
//        }
//        areas.setNextList(list);
//        return areas;
//    }

    @Override
    public List<Areas> findByParentCode(String parentCode) {
        LambdaQueryWrapper<Areas> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Areas::getParentCode, parentCode);
        wrapper.orderByAsc(Areas::getCode);
        return baseMapper.selectList(wrapper);
    }

    @Override
    public List<Areas> findByProvince(String provinceCode) {
        List<Areas> list = this.findByParentCode(provinceCode);
//        for (Areas areas : list) {
//            areas.setNextList(this.findByParentCode(areas.getCode()));
//        }
        return list;
    }

    public Areas findByCode(String code) {
        LambdaQueryWrapper<Areas> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Areas::getCode, code);
        return baseMapper.selectOne(wrapper);
    }

    /**
     * 迭代循环城市信息
     *
     * @param obj
     * @param list
     * @param parentCode
     */
    private void iterationAreas(JSONObject obj, List<Areas> list, String parentCode) {
        Areas areas = new Areas();
        areas.setCode(obj.getString(ADCODE));
        areas.setParentCode(parentCode);
        areas.setName(obj.getString(NAME));
        /**
         * 定位信息
         */
        String location = obj.getString(CENTER);
        if (ObjectUtil.isNotEmpty(location)) {
            String[] locations = location.split(",");
            //设置经度
            areas.setLon(new BigDecimal(locations[0]));
            //设置纬度
            areas.setLat(new BigDecimal(locations[1]));
        }
        //不属于街道直接添加
        if (!"street".equalsIgnoreCase(obj.getString("level"))) {
            list.add(areas);
        }
        if (obj.containsKey(DISTRICTS) && ObjectUtil.isNotEmpty(obj.getJSONArray(DISTRICTS))) {
            JSONArray districts = obj.getJSONArray(DISTRICTS);
            for (int i = 0; i < districts.size(); i++) {
                iterationAreas(districts.getJSONObject(i), list, areas.getCode());
            }
        }
    }
}
